/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.playground.client.websockets.application;

import com.playground.client.websockets.entity.message.Action;
import com.playground.client.websockets.entity.message.request.EnterQueueRequestMesage;
import com.playground.client.websockets.entity.message.request.RequestMessage;
import com.playground.client.websockets.entity.message.response.ResponseMessage;
import com.playground.client.websockets.socket.PlayerSocket;
import com.playground.client.websockets.util.JsonUtil;
import com.playground.core.entity.GameTitle;
import com.playground.core.entity.Invitation;
import com.playground.core.entity.Room;
import com.playground.core.repository.GameTitleRepository;
import com.playground.core.service.LoginService;
import com.playground.core.service.QueueService;
import com.playground.core.service.RoomService;
import com.sun.grizzly.tcp.Request;
import com.sun.grizzly.websockets.ProtocolHandler;
import com.sun.grizzly.websockets.WebSocket;
import com.sun.grizzly.websockets.WebSocketListener;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author Tiago Peres
 */
public class GameSelectionApplication extends PlaygroundApplication {
    private static HashMap<Long, PlayerSocket> playerIndex = new HashMap<Long, PlayerSocket>();

    private GameTitleRepository gameTitleRepository;
    private QueueService queueService;
    private RoomService roomService;
    
    public GameSelectionApplication(LoginService loginService, GameTitleRepository gameTitleRepository, QueueService queueService, RoomService roomService){
        super(loginService);
        this.gameTitleRepository = gameTitleRepository;
        this.queueService = queueService;
        this.roomService = roomService;
    }
    
    @Override
    public WebSocket createWebSocket(ProtocolHandler handler, WebSocketListener... listeners) {
        /*if (!InvitationObserver.getInstance().isRunning()){
            InvitationObserver.getInstance().start();
        }*/
        return new PlayerSocket(handler, listeners);
    }

    @Override
    public boolean isApplicationRequest(Request rqst) {
        return rqst.requestURI().toString().endsWith("/select-game");
        //return false;
    }
    
    @Override
    protected boolean parseMessage(PlayerSocket socket, RequestMessage message){
        switch (message.getAction()){
            case enterQueue:
                EnterQueueRequestMesage enterQueueMsg = (EnterQueueRequestMesage) message;
                GameTitle gameTitle = gameTitleRepository.findOne(enterQueueMsg.getGameTitleId());
                addToQueue(socket, gameTitle);
                break;
            case joinGame:
                joinGame(socket);
        }
        return true;
    }
    
    @Override
    protected boolean registerPlayerToSocket(PlayerSocket socket, long playerId, String key) throws CloneNotSupportedException{
        boolean returnValue = super.registerPlayerToSocket(socket, playerId, key);
        playerIndex.put(playerId, socket);
        return returnValue;
    }
    
    // methods called by parseMessage, according to the message received
  
    /**
     * Adds the player to the queue of the specified game.
     * 
     * @param player the websocket corresponding to the player to queue
     * @param gameTitle the game the user is queuing for
     */
    private void addToQueue(PlayerSocket socket, GameTitle gameTitle){
        boolean error = true;
        if (null != gameTitle){
            Room room = queueService.addToQueue(Arrays.asList(socket.getPlayer()), gameTitle);
            if (null != room) error = false;
        }
        if (error){
            ResponseMessage msg = new ResponseMessage();
            msg.setAction(Action.enterQueue);
            msg.setSuccess(false);
            socket.send(JsonUtil.getGson().toJson(msg, ResponseMessage.class));
        }
    }
    
    /**
     * Removes a player from the queue he's in
     * 
     * @param player the player to be removed from the queue
     */
    private void removePlayerFromQueue(PlayerSocket socket){
        // queueService.removePlayerFromQueue(player.getPlayer())
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    
    /**
     * Registers a guest answer (true for yes, false for no) to a given
     * invitation.
     * 
     * @param invitation the invitation to be answered
     * @param guest the guest answering the invitation
     * @param answer the answer, true for yes, false for no
     */
    private void answerInvitation(Invitation invitation, PlayerSocket guestSocket, boolean answer){
        // invitationService.answerInvitation(invitation, guest.getPlayer(), answer)
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    
    /**
     * If some invited player didn't answer or answered no, the host has to
     * confirm he still wants to play with just the players who said yes.
     * 
     * @param host the invitation's creator
     */
    private void confirmInvitation(PlayerSocket hostSocket){
        // remove the invitation;
        // enter the queue for the specified gameTitle with all the guests who answered yes;
        // if the queue is already full, send a message to each player asking if they wanna join the game;
        // else send a message to each player informim they entered a queue.
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * Sends a json to the player with all the games avaiable for him.
     * 
     * @param player the player requesting the avaiable games
     */
    private void getAvaiableGames(PlayerSocket socket){
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * Sends a json to the player contaning all his/her online friends.
     * 
     * @param player the player requesting his/her online friends
     */
    private void getOnlineFriends(PlayerSocket socket){
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * Creates an invitation to play a specified gameTitle. An invitation is
     * made by a host to his/her guests.
     * 
     * @param host the invitation's creator
     * @param guests the players invited by the host
     * @param gameTitle the game title to be played
     */
    private void inviteFriends(PlayerSocket hostSocket, List<PlayerSocket> guestsSockets, GameTitle gameTitle){
        // Call invitationService.createInvitation(inviter, invited, game);
        // Send a message to each invited friend
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * When the room becomes full, the players in it are asked if they wanna join
     * the game. To answer yes to the question, this method should be called.
     * If all players in the room (player.getRoom) has called startGame(), all
     * of them should be redirected to the page of the corresponding game.
     * With the redirection message the roomId should also be sent.
     * 
     * @param player the player joing the game 
     */
    private void joinGame(PlayerSocket socket){
        Iterator<PlayerSocket> avaiable = playerIndex.values().iterator();
        System.out.println("Avaiable sockets:");
        while(avaiable.hasNext()){
            PlayerSocket p = avaiable.next();
            System.out.println("Player id: " + p.getPlayer().getId());
            System.out.println("Room id: " + ((null == p.getPlayer().getRoom()) ? "oops, room is null" : p.getPlayer().getRoom().getId()));
            System.out.println("Listeners size: " + p.getListeners().size());
            System.out.println("Network handler is " + ((null == p.getNetworkHandler()) ? "null" : "not null"));
            System.out.println("Connected: " + (p.isConnected() ? "true" : "false"));
        }
        queueService.confirmGame(socket.getPlayer(), socket.getPlayer().getRoom());
    }
    
    public static PlayerSocket getPlayerSocketByPlayerId(long id) {
        return playerIndex.get(id);
    }
    
}
